home *** CD-ROM | disk | FTP | other *** search
- /*
- * event.c - startup, stopping, and the main event loop
- */
-
- #include <quickdraw.h>
- #include <memory.h>
- #include <font.h>
- #include <window.h>
- #include <dialog.h>
- #include <osutil.h>
- #include <menu.h>
- #include <event.h>
- #include <textedit.h>
- #include <desk.h>
- #include <control.h>
- #include <toolutil.h>
-
- #define DATA
- #include "ival.h"
- #undef DATA
-
- /*
- * ctbuts[] - buttons for the "Control" window pane
- */
-
- #define CTSTRS 134 /* STR# */
- #define CT_NEXT 0 /* "Next test" */
- #define CT_PLAY 1 /* "Play the tones" */
- #define CT_COUNT 2
- static ControlHandle ctbuts[CT_COUNT];
-
- /*
- * main() - start the program.
- */
-
- main()
- {
- static WindowRecord wrecord; /* Storage for window record. */
-
- /*
- * Initialize our program. It seems best to handle:
- * Memory inits first, ToolBox inits second, then the program variables'
- * inits. Note that the order of inits is important; see "Using the
- * Dialog Manager" in the Dialog Mgr section.
- */
-
- setupmemory();
- InitGraf(&thePort); InitFonts(); InitWindows(); InitMenus(); TEInit();
- InitDialogs((ProcPtr) 0); InitCursor();
- SetEventMask(everyEvent - keyUpMask); /* set default event mask */
-
- /*
- * Get the port which is the whole screen, to use when deactivating
- * our window. This prevents the current grafPort pointer from
- * ever dangling.
- */
- GetWMgrPort(&screenport);SetPort(screenport);
-
- /*
- * GetNewWindow posts an update event for the new window,
- * so it will be redrawn right away. (-1 is the frontmost window)
- * Set the default text drawing for our window.
- */
- windoc = GetNewWindow(WINDOWID, &wrecord, (long) -1);
- SetPort(windoc); TextFont(systemFont);
-
- /*
- * set who initially provides what.
- */
-
- progtasks.notate = TRUE;
- studtasks.notate = FALSE;
- progtasks.name = FALSE;
- studtasks.name = TRUE;
- progtasks.sound = TRUE;
- studtasks.sound = FALSE;
-
- /*
- * Set how notes are played
- * and whether accidentals are allowed.
- */
-
- any_seq = SEQ_MEL;
- acc_ok = FALSE;
-
- setupmenus(); /* pull in and setup our menus */
- fillwindow(); /* auto-shape the window */
- mus4init(); /* init the four-part music player */
- nexttest();
- while (doevent()) /* do the event-driven part of the program */
- ;
- closeup();
- }
-
- /*
- * closeup() - prepare to exit the program. (called before exiting).
- * Restore the state of the machine so the finder will be happy.
- */
- closeup()
- {
- InitCursor();
- SetEventMask(everyEvent - keyUpMask);
- }
-
- /*
- * fillcntl() - fill in the 'control' pane.
- */
-
- fillcntl()
- {
- short numstrs; /* number of strings in the current STR# resource*/
- Point delta; /* a temporary distance */
- short width; /* a width (in pixels) */
- Rect tmprect; /* a temporary variable */
-
- /*
- * put all the control buttons in a horizontal line just below the
- * top of the control rectangle.
- */
-
- width = strswidth(CTSTRS, &numstrs) + BUTEXTRAH;
- tmprect.left = (cntlrect.left + cntlrect.right) / 2 -
- ((width + BUTHMARG) * numstrs) / 2;
- tmprect.right = tmprect.left + width;
- tmprect.top = cntlrect.top + HMARGIN;
- tmprect.bottom = tmprect.top + BUTHEIGHT;
- delta.h = width + BUTHMARG;
- delta.v = 0;
- makeradcol(ctbuts, BUTPROCID, CTSTRS, &tmprect, delta.h, delta.v);
- }
-
- /*
- * cntlpress() - handle a button press within the Control pane.
- */
-
- cntlpress(whichcontrol)
- ControlHandle whichcontrol;
- {
- short semi1;
- short semi2;
- struct atone midc;
- short butidx; /* index of the pressed button */
-
- /*
- * If the button was 'Next', start the next test.
- * if the button was 'Play',
- * play the desired harmonic or melodic interval.
- */
-
- for (butidx = 0; butidx < CT_COUNT; ++butidx) {
- if (whichcontrol == ctbuts[butidx]) break;
- }
- switch (butidx) {
- case CT_NEXT:
- nexttest();
- break;
- case CT_PLAY:
- midc.degree = DEG_MIDC;
- midc.chrome = CH_NAT;
- semi1 = tonetosemi(&curtone[0]) - tonetosemi(&midc);
- semi2 = tonetosemi(&curtone[1]) - tonetosemi(&midc);
- switch (cur_seq) {
- case SEQ_HARM:
- mus4play(60, semi1, semi2, 1000, 1000);
- break;
- case SEQ_MEL:
- mus4play(30, semi1, 1000, 1000, 1000);
- mus4play(30, semi2, 1000, 1000, 1000);
- break;
- }
- break;
- }
- }
-
- /*
- * nexttest() - choose a new exercise.
- */
-
- nexttest()
- {
- short mindeg, maxdeg; /* limits of degrees to choose */
- short degs; /* # of degrees in the interval */
- short semis; /* base # of semitones in the interval */
- short hasname[NUM_CH][NUM_CH]; /* tone1.chrome to tone2.chrome named?*/
- short ch1, ch2; /* .chrome for each tone */
- short nummods; /* number of legal chromatic mods */
- short modidx; /* index of the chosen modifier */
- struct ivinfo *ivp;
- short i;
- short tonetosemi();
-
- pickkey();
- InvalRect(&scorerect);
-
- /*
- * Pick a degree for each of the tones;
- * The second must fall within an octave of the first
- * (and within the limits of the score range).
- */
-
- curtone[0].degree = randint(DEGPERSCORE);
- curtone[0].chrome = CH_NAT;
-
- mindeg = curtone[0].degree - DEGPEROCT;
- if (mindeg < 0) mindeg = 0;
- maxdeg = curtone[0].degree + DEGPEROCT;
- if (maxdeg > DEGPERSCORE - 1) maxdeg = DEGPERSCORE - 1;
- curtone[1].degree = mindeg + randint(maxdeg - mindeg + 1);
- curtone[1].chrome = CH_NAT;
-
- degs = curtone[1].degree - curtone[0].degree;
- if (degs < 0) degs = -degs;
-
- /*
- * If it's not ok to have accidentals,
- * use the chromatic modifications of the key signature.
- * Otherwise, pick random, but possible, chromatic changes to the two tones:
- * First find what (and how many) changes are possible;
- * Then pick one of them.
- */
-
- if (!acc_ok) {
- for (i = 0; i < NUMTONES; ++i) {
- curtone[i].chrome = chromeofdeg(curtone[i].degree);
- }
- } else {
- nummods = 0;
- for (ch1 = CH_FLAT; ch1 <= CH_SHARP; ++ch1) {
- for (ch2 = CH_FLAT; ch2 <= CH_SHARP; ++ch2) {
- hasname[ch1 - CH_FLAT][ch2 - CH_FLAT] = FALSE;
- semis = tonetosemi(&curtone[1]) + ch2 -
- (tonetosemi(&curtone[0]) + ch1);
- if ((curtone[0].degree < curtone[1].degree && semis < 0) ||
- (curtone[0].degree > curtone[1].degree && semis > 0)) {
- continue; /* adjustments cross */
- }
- if (semis < 0) semis = -semis;
- for (ivp = &ivinfo[0]; ivp->semis >= 0; ++ivp) {
- if (ivp->semis == semis && ivp->degs == degs) {
- hasname[ch1 - CH_FLAT][ch2 - CH_FLAT] = TRUE;
- ++nummods;
- break;
- }
- }
- }
- }
- if (nummods > 0) {
- modidx = randint(nummods);
- for (ch1 = CH_FLAT; ch1 <= CH_SHARP && modidx >= 0; ++ch1) {
- for (ch2 = CH_FLAT; ch2 <= CH_SHARP && modidx >= 0; ++ch2) {
- if (hasname[ch1 - CH_FLAT][ch2 - CH_FLAT]) {
- if (--modidx < 0) {
- curtone[0].chrome = ch1;
- curtone[1].chrome = ch2;
- }
- }
- }
- }
- }
- }
-
- /*
- * get the size and type of the new interval.
- */
-
- semis = tonetosemi(&curtone[1]) - tonetosemi(&curtone[0]);
- if (semis < 0) semis = -semis;
-
- for (ivp = &ivinfo[0]; ivp->semis >= 0; ++ivp) {
- if (ivp->semis == semis && ivp->degs == degs) {
- curisize = degs;
- curitype = ivp->qual;
- break;
- }
- }
-
- /*
- * choose how to play the tones:
- * If the type is restricted, do just the restricted type;
- * Otherwise, choose a type at random.
- */
-
- if (any_seq != SEQ_MIX) {
- cur_seq = any_seq;
- } else {
- cur_seq = randint(NUM_SEQ);
- }
-
- newname();
- newtones();
- }
-
- /*
- * tonetosemi() - give the semitone number (relative to Low C) of the
- * given tone.
- */
-
- short
- tonetosemi(tp)
- struct atone *tp; /* the tone to convert */
- {
- short semi; /* the result to return */
- static short semodeg[DEGPEROCT] = {
- 0, /* C */
- 2, /* D */
- 4, /* E */
- 5, /* F */
- 7, /* G */
- 9, /* A */
- 11 /* B */
- };
-
- semi = (tp->degree / DEGPEROCT) * SEMPEROCT;
- semi += semodeg[tp->degree % DEGPEROCT];
- semi += tp->chrome;
- return(semi);
- }
-